package com.lastproject.ejb.dao;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Date;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.xml.bind.DatatypeConverter;

import com.lastproject.dto.TraineeDTO;
import com.lastproject.ejb.entities.Role;
import com.lastproject.ejb.entities.Trainee;
import com.lastproject.ejb.entities.User;
import com.lastproject.ejb.service.MailSender;
import com.lastproject.ejb.service.PasswordEncryption;
import com.lastproject.ejb.util.TraineeConversion;

/**
 * Session Bean implementation class TraineeDAO
 */
@Stateless
public class TraineeDAO implements TraineeDAORemote {

	@PersistenceContext
	EntityManager entityManager;

	@EJB
	TraineeConversion conv;

	public TraineeDAO() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void create(TraineeDTO traineeDTO) {
		System.out.println("in trainee dao create");

		// initial password, represented as a string
		String tempPass = traineeDTO.getPassword();
		String password_encrypted2 = "";

		System.out.println("pass from gui: " + tempPass);

		try {

			// initial password after being hashed using SHA-1
			// represented as byte[]
			byte[] hashedPassword = new PasswordEncryption()
			.getEncryptedPassword(tempPass,
					new PasswordEncryption().getSalt());

			// hashed password stored as string
			// this version of the password will be stored in the db
			password_encrypted2 = DatatypeConverter
					.printHexBinary(hashedPassword);
			traineeDTO.setPassword(password_encrypted2);
		} catch (NoSuchAlgorithmException | InvalidKeySpecException
				| UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		
		Trainee auxTrainee = conv.fromDTO(traineeDTO);
		List<Role> roles = conv.convertRolesFromDTO(traineeDTO);
		
		// set user for roles
		for(int i=0; i<roles.size(); i++) {
			List<User> userListForRole = new ArrayList<>();
			User myUser = auxTrainee;
			userListForRole.add(myUser);
			System.out.println(roles.get(i).toString());
		}
		
		// set roles for user
		auxTrainee.setRoles(roles);
		
		
		entityManager.persist(auxTrainee);
		
		// send email with instructions to activate account
		sendInstructionsEmail("newAccount", traineeDTO.getWorkEmail(),
				traineeDTO.getUsername(), password_encrypted2);
	}

	@Override
	public TraineeDTO findById(int id) {
		Trainee trainee = entityManager.find(Trainee.class, id);
		
		TraineeDTO traineeDTO = conv.fromEntity(trainee);
		
		List<Integer> rolesID = conv.convertRolesFromEntity(trainee);
		traineeDTO.setRolesIdList(rolesID);		
		
		return traineeDTO;
	}

	@Override
	public List<TraineeDTO> getAll() {
		List<Trainee> traineeList = entityManager.createQuery("Select t from Trainee t",
				Trainee.class).getResultList();

		List<TraineeDTO> traineesDTO = new ArrayList<TraineeDTO>();

		for (Trainee trainee : traineeList) {
			TraineeDTO tDTO = new TraineeDTO();
			tDTO = conv.fromEntity(trainee);
			traineesDTO.add(tDTO);

		}

		return traineesDTO;
	}

	@Override
	public void edit(TraineeDTO traineeDTO) {
		
		Trainee auxTrainee = conv.fromDTO(traineeDTO);
		List<Role> roles = conv.convertRolesFromDTO(traineeDTO);
		
		// set user for roles
		for(int i=0; i<roles.size(); i++) {
			List<User> userListForRole = new ArrayList<>();
			User myUser = auxTrainee;
			userListForRole.add(myUser);
			System.out.println(roles.get(i).toString());
		}

		// set roles for user
		auxTrainee.setRoles(roles);
		
		entityManager.merge(auxTrainee);
		
//		entityManager.merge(conv.fromDTO(traineeDTO));
	}

	@Override
	public void remove(TraineeDTO traineeDTO) {
		Trainee trainee = entityManager.find(Trainee.class, conv.fromDTO(traineeDTO)
				.getId());
		entityManager.remove(trainee);
	}
	
	public void sendInstructionsEmail(String emailPurpose,
			String receiverEmail, String receiverUsername, String encryptPass) {
		MailSender ms = new MailSender();

		String emailSender = "no-reply@msg-systems.com";
		String emailSubject = "";
		String emailContent = "";

		// property file that contains ip address of server
		// on which project is run
		// at the moment - localhost
		Properties ipConfigFile = new Properties();
		// property file is stored in META-INF folder
		InputStream myIS = getClass().getClassLoader().getResourceAsStream(
				"META-INF/ipconfigs.properties");

		try {
			// open property file
			ipConfigFile.load(myIS);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// get value of "ip" property
		String ipAddress = ipConfigFile.getProperty("ip");
		String firstAccessLink = ipAddress
				+ "LastProjectWeb/faces/changePassword.xhtml" + "?logUsername="
				+ receiverUsername + "&logPassword=" + encryptPass;

		switch (emailPurpose) {

		case "newAccount":
			emailSubject = "Your account was created";
			emailContent = "Click the link provided below and follow the instructions"
					+ " to activate your account.\n\n" + firstAccessLink;
			break;
		}

		ms.sendMail(emailSender, receiverEmail, emailSubject, emailContent);
	}

	@Override
	public List<TraineeDTO> findByCriteria(String name,
			String position, String employmentType, Date startEmploymentDate,
			Date endEmploymentDate, Date startLastMedCheckDate,
			Date endLastMedCheckDate, boolean enabledAccount,
			float startSalary, float endSalary) {

		List<TraineeDTO> traineeDTOList= new ArrayList<TraineeDTO>();

		String selectPart = "SELECT DISTINCT t FROM Trainee t";
		StringBuilder wherePart = new StringBuilder();
		wherePart.append(" WHERE ");

		boolean previous = false;

		if (!name.isEmpty()) {
			wherePart.append("("
					+ "(t.firstname LIKE '%" + name + "%') "
					+ "or (t.lastname LIKE '%" + name + "%') "
					+ "or (concat(t.firstname, ' ', t.lastname) = '" + name + "') "
					+ "or (concat(t.lastname, ' ', t.firstname) = '" + name + "')"
					+ ")");
			previous = true;
		}

		if (!position.isEmpty()) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.position = '" + position + "')");
			previous = true;
		}

		if (!employmentType.isEmpty()) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.employmentType = '" + employmentType + "')");
			previous = true;
		}

		if ((startEmploymentDate != null) && (endEmploymentDate != null) && 
				(startEmploymentDate.compareTo(endEmploymentDate) < 0)) {
			// between start and end
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.employmentDate BETWEEN '"
					+ new java.sql.Date(startEmploymentDate.getTime()) + "' AND '" 
					+ new java.sql.Date(endEmploymentDate.getTime()) + "')");
			previous = true;
		} else if (startEmploymentDate != null && (endEmploymentDate == null)) {
			// from start onwards
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.employmentDate > '" + new java.sql.Date(startEmploymentDate.getTime()) + "')");
			previous = true;
		}

		if ((startLastMedCheckDate != null) && (endLastMedCheckDate != null) && 
				(startLastMedCheckDate.compareTo(endLastMedCheckDate) < 0)) {
			// between start and end
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.medCheckUpDate BETWEEN '"
					+ new java.sql.Date(startLastMedCheckDate.getTime()) + "' AND '" 
					+ new java.sql.Date(endLastMedCheckDate.getTime()) + "')");
			previous = true;
		} else if (startLastMedCheckDate != null && (endLastMedCheckDate == null)) {
			// from start onwards
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.medCheckUpDate > '" + new java.sql.Date(startLastMedCheckDate.getTime()) + "')");
			previous = true;
		}

		if (enabledAccount == true) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.enabled = " + 1 + ")");
			previous = true;
		} else {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.enabled = " + 0 + ")");
			previous = true;
		}

		if ((startSalary == endSalary) && startSalary != 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.salary = " + startSalary + ")");
			previous = true;
		} else if (startSalary != 0 && endSalary != 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.salary BETWEEN " + startSalary + " AND "
					+ endSalary + ")");
			previous = true;
		} else if (startSalary != 0 && endSalary == 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.salary > " + startSalary + ")");
			previous = true;
		} else if (startSalary == 0 && endSalary != 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(t.salary < " + endSalary + ")");
			previous = true;
		}

		String fullQuery = selectPart + wherePart.toString();
		// System.out.println(fullQuery);
		List<Trainee> traineeList = new ArrayList<Trainee>();
		traineeList = entityManager.createQuery(fullQuery,
				Trainee.class).getResultList();

		for (Trainee t : traineeList) {
			traineeDTOList.add(conv.fromEntity(t));
		}

		return traineeDTOList;
	}

}
